<template>
	<div ref="tabScrollbarRef" class="nav-tabs">
		<el-dropdown v-for="(menuVo, index) in navTabsStore.openedTabs" :key="'openedTabs_' + index" :ref="dropdownRefs.set" class="tab-dropdown" role="navigation"
		             trigger="contextmenu">
			<div
					:ref="tabRefs.set"
					:class="navTabsStore.activeIndex === index ? 'active' : ''"
					class="nav-tab-item"
					@click="onTab(menuVo)"
					@click.middle.prevent="middleCloseTab(menuVo)"
					@contextmenu.prevent="onContextmenu(index)"
			>
				<icon v-if="webConfigStore.layout.tabIcon" :name="menuVo.meta.icon || webConfigStore.layout.menuDefaultIcon"
				      style="margin-right: 5px"/>
				{{ $t(menuVo.meta.title) }}
				<icon v-if="navTabsStore.openedTabs.length > 1 && !menuVo.meta.affix" class="close-icon" name="el-icon-Close"
				      size="15" @click.stop="closeTab(menuVo)"/>
			</div>
			<template #dropdown>
				<el-dropdown-menu>
					<el-dropdown-item icon="el-icon-Refresh" @click="onContextmenuItem({name: 'refresh', data: menuVo})">重新加载</el-dropdown-item>
					<el-dropdown-item :disabled="menuVo.meta.affix || navTabsStore.openedTabs.length <= 1" icon="el-icon-Close"
					                  @click="onContextmenuItem({name: 'close', data: menuVo})">关闭标签页
					</el-dropdown-item>
					<el-dropdown-item @click="onContextmenuItem({name: 'fullScreen', data: menuVo})">
						<icon name="local-cus-fullscreen" style="margin-right: 5px"/>
						标签页全屏
					</el-dropdown-item>
					<el-dropdown-item :disabled="checkCloseLeftDisabled(menuVo)" divided icon="el-icon-ArrowLeftBold"
					                  @click="onContextmenuItem({name: 'closeLeft', data: menuVo})">关闭左侧标签页
					</el-dropdown-item>
					<el-dropdown-item :disabled="checkCloseRightDisabled(menuVo)" icon="el-icon-ArrowRightBold"
					                  @click="onContextmenuItem({name: 'closeRight', data: menuVo})">关闭右侧标签页
					</el-dropdown-item>
					<el-dropdown-item :disabled="checkCloseOtherDisabled(menuVo)" divided @click="onContextmenuItem({name: 'closeOther', data: menuVo})">
						<icon name="fa fa-compress"/>
						关闭其他标签页
					</el-dropdown-item>
					<el-dropdown-item :disabled="checkCloseAllDisabled()" icon="el-icon-CircleClose" @click="onContextmenuItem({name: 'closeAll', data: menuVo})">
						关闭全部标签页
					</el-dropdown-item>
				</el-dropdown-menu>
			</template>
		</el-dropdown>
	</div>
</template>

<script lang="ts" setup>
import {nextTick, onBeforeUnmount, onMounted, ref, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import {useWebConfigStore} from '@/stores/modules/webConfig.store'
import {useNavTabsStore} from '@/stores/modules/navTabs.store'
import {useEventListener, useTemplateRefsList} from '@vueuse/core'
import horizontalScroll from '@/utils/horizontalScrollUtil'
import {useUserStore} from '@/stores/modules/user.store'
import {findInTreeArray, messageError} from '@/utils/commonUtil'
import {homeRoute} from '@/router/static'
import screenFull from 'screenfull'
import {type DropdownInstance, ElMessage} from 'element-plus'
import {debounce, type DebouncedFunc, find} from 'lodash-es'
import Icon from '@/components/icon.vue'
import {i18n} from '@/lang'
import type {MenuVO} from '@/model/route'
import {checkLogin} from '@/utils/authUtil'

const route = useRoute()
const router = useRouter()
const webConfigStore = useWebConfigStore()
const navTabsStore = useNavTabsStore()
const userStore = useUserStore()
const tabScrollbarRef = ref()
const tabRefs = useTemplateRefsList<HTMLDivElement>()
const dropdownRefs = useTemplateRefsList<DropdownInstance>()

watch(() => route.path, value => {
	setCurrentTab(value)
})

/**
 * 处理激活标签的样式和滚动条
 * 触发契机：
 * ① 切换显示tab图标
 * ② 切换tab
 * ③ 切换语言
 */
watch([() => webConfigStore.layout.tabIcon, i18n.global.locale], () => {
	selectActiveTab()
})

const onTab = (menu: MenuVO) => {
	router.push(menu)
	navTabsStore.setActiveRoute(menu)
}

// 是否禁用关闭左侧标签页
const checkCloseLeftDisabled = (menu: MenuVO): boolean => {
	let disabled = true
	const menuIndex = navTabsStore.openedTabs.indexOf(menu)
	for (const openedMenu of navTabsStore.openedTabs) {
		const index = navTabsStore.openedTabs.indexOf(openedMenu)
		if (index < menuIndex && !openedMenu.meta.affix) {
			disabled = false
		}
	}
	return disabled
}

// 是否禁用关闭右侧标签页
const checkCloseRightDisabled = (menu: MenuVO): boolean => {
	let disabled = true
	const menuIndex = navTabsStore.openedTabs.indexOf(menu)
	for (const openedMenu of navTabsStore.openedTabs) {
		const index = navTabsStore.openedTabs.indexOf(openedMenu)
		if (index > menuIndex && !openedMenu.meta.affix) {
			disabled = false
		}
	}
	return disabled
}

// 是否禁用关闭其他
const checkCloseOtherDisabled = (menu: MenuVO): boolean => {
	if (navTabsStore.openedTabs.length <= 1) {
		return true
	} else {
		for (const openedMenu of navTabsStore.openedTabs) {
			if (!openedMenu.meta.affix) {
				if (openedMenu.meta.fullPath !== menu.meta.fullPath) {
					return false
				}
			}
		}
		return true
	}
}

// 是否禁用关闭全部
const checkCloseAllDisabled = (): boolean => {
	if (navTabsStore.openedTabs.length <= 1) {
		return true
	} else {
		for (const openedMenu of navTabsStore.openedTabs) {
			if (!openedMenu.meta.affix) {
				return false
			}
		}
		return true
	}
}

// 切换tab后处理滚动条滚动
const selectActiveTab = () => {
	nextTick(() => {
		const dom = tabRefs.value[navTabsStore.activeIndex]
		if (!dom) {
			return
		}
		if (!tabScrollbarRef.value) {
			return
		}
		dom.scrollIntoView({
			behavior: 'smooth',
			block: 'center',
			inline: 'center'
		})
	})
}

const toLastTab = () => {
	const lastTab = navTabsStore.openedTabs.slice(-1)[0]
	if (lastTab) {
		router.push(lastTab.meta.fullPath)
	} else {
		router.push('/')
	}
}

const closeTab = (menu: MenuVO) => {
	navTabsStore.closeTab(menu)
	if (navTabsStore.activeTab!.meta.fullPath === menu.meta.fullPath) {
		toLastTab()
	} else {
		setCurrentTab(route.path, false)
	}
}

const middleCloseTab = (menu: MenuVO) => {
	const computedStyle: CSSStyleDeclaration = window.getComputedStyle(tabScrollbarRef.value)
	// 存在横向滚动条时，暂时关闭“鼠标中键关闭tab”的功能
	if (computedStyle.width !== computedStyle.minWidth) {
		return
	}
	if (!menu.meta.affix && navTabsStore.openedTabs.length > 1) {
		closeTab(menu)
	}
}
const closeLeftTab = (menu: MenuVO) => {
	navTabsStore.closeLeftTabs(menu)
	if (!navTabsStore.openedTabs.some(item => item.meta.fullPath === navTabsStore.activeTab!.meta.fullPath)) {
		router.push(menu.meta.fullPath)
	} else {
		setCurrentTab(route.path, false)
	}
}

const closeRightTab = (menu: MenuVO) => {
	navTabsStore.closeRightTabs(menu)
	if (!navTabsStore.openedTabs.some(item => item.meta.fullPath === navTabsStore.activeTab!.meta.fullPath)) {
		toLastTab()
	}
}

const closeOtherTab = (menu: MenuVO) => {
	navTabsStore.closeTabs(menu)
	if (navTabsStore.activeTab!.meta.fullPath !== menu.meta.fullPath) {
		router.push(menu.meta.fullPath)
	} else {
		setCurrentTab(menu, false)
	}
}

const closeAllTab = () => {
	navTabsStore.closeTabs()
	if (!find(navTabsStore.openedTabs, item => item.meta.fullPath === navTabsStore.activeTab!.meta.fullPath)) {
		if (homeRoute.redirect === navTabsStore.activeTab!.meta.fullPath) {
			setCurrentTab(homeRoute.redirect)
		} else {
			router.push(<string>homeRoute.redirect)
		}
	}
}

const onContextmenu = (index: number) => {
	for (const dropdown of dropdownRefs.value) {
		if (dropdownRefs.value.indexOf(dropdown) !== index) {
			dropdown.handleClose()
		}
	}
}

const onContextmenuItem = async (item: { name: string, data: MenuVO }) => {
	const {name} = item
	const menu = <MenuVO>item.data
	if (!menu) {
		return
	}
	switch (name) {
		case 'refresh':
			if (route.path !== menu.meta.fullPath) {
				await router.push(menu)
			}
			navTabsStore.refreshTab(menu)
			break
		case 'close':
			closeTab(menu)
			break
		case 'closeLeft':
			closeLeftTab(menu)
			break
		case 'closeRight':
			closeRightTab(menu)
			break
		case 'closeOther':
			closeOtherTab(menu)
			break
		case 'closeAll':
			closeAllTab()
			break
		case 'fullScreen':
			if (route.path !== menu?.meta.fullPath) {
				await router.push(menu?.meta.fullPath as string)
			}
			if (!screenFull.isEnabled) {
				ElMessage.warning('您的浏览器不支持全屏，请更换浏览器再试~')
				return
			}
			await screenFull.toggle()
			break
	}
}

/**
 * 使传入的tab处于选中状态，tab当前不存在则打开
 * @param newRoute @{@link MenuVO}或路由的meta.fullPath
 * @param addFlag 是否添加新tab，默认为true
 */
const setCurrentTab = (newRoute: MenuVO | string, addFlag: boolean = true): void => {
	if (typeof newRoute === 'string') {
		const findMenu = findInTreeArray(userStore.menus, (menu: MenuVO) => menu.meta.fullPath === newRoute)
		if (!findMenu) {
			const errorMessage = `无法根据 fullPath （${newRoute}）匹配到菜单，请检查 fullPath 的值是否有误`
			messageError(errorMessage)
			throw Error(errorMessage)
		}
		newRoute = findMenu
	}
	// 添加tab
	if (addFlag) {
		navTabsStore.addTab(newRoute)
	}
	// 设置激活的tab
	navTabsStore.setActiveRoute(newRoute)
	// 滚动条滚动
	selectActiveTab()
}

const onSetCurrentTab: DebouncedFunc<() => typeof onSetCurrentTab> = debounce(() => {
	setTimeout(() => {
		selectActiveTab()
	}, 200)
	return onSetCurrentTab
}, 100, {
	leading: true,
	trailing: false,
	maxWait: 100
})

onMounted(() => {
	new horizontalScroll(tabScrollbarRef.value)
	useEventListener(window, 'resize', onSetCurrentTab)
	setTimeout(async () => {
		// 检查登录状态，如果未登录或登录已过期，则不执行setCurrentTab()
		const errorMessage = await checkLogin()
		if (errorMessage) {
			return
		}
		setCurrentTab(route.path)
	}, 200)
})

onBeforeUnmount(() => {
	window.removeEventListener('resize', onSetCurrentTab)
})

</script>

<style lang="scss" scoped>

.nav-tabs {
	//align-items: v-bind('webConfigStore.layout.layoutMode == "Default" ? "start" : "normal"');

	margin-right: var(--cus-main-space);
	padding: 0 10px;
	overflow-x: auto;
	overflow-y: hidden;
	scrollbar-width: none;

	&::-webkit-scrollbar {
		height: 5px;
	}

	&::-webkit-scrollbar-thumb {
		background: grey;
		border-radius: var(--el-border-radius-base);
		-webkit-box-shadow: none;
		box-shadow: none;
	}

	&::-webkit-scrollbar-track {
		background: v-bind('webConfigStore.layout.layoutMode == "Default" ? "none" : webConfigStore.getColorVal("headerBarBackground")');
	}

	&:hover {
		&::-webkit-scrollbar-thumb:hover {
			background: lightgrey;
		}
	}
}

.nav-tab-item {
	height: 40px;
	white-space: nowrap;
}
</style>
